package wang.lxl.concurrent.lockTest;

/**
 * 生产者,消费者错误写法(运行示例图:等待唤醒机制图1)
 */
public class ProducerAndConsumerTest {
    public static void main(String[] args) {
        // 测试1
//        Clerk clerk1 = new Clerk1();
//        Producer pro = new Producer(clerk1);
//        Consumer consumer = new Consumer(clerk1);
//        new Thread(pro, "生产者A").start();
//        new Thread(consumer, "消费者B").start();

        // 测试2(虚假唤醒)
//        Clerk clerk2 = new Clerk2();
//        Producer pro = new Producer(clerk2);
//        Consumer consumer = new Consumer(clerk2);
//        new Thread(pro, "生产者A").start();
//        new Thread(consumer, "消费者B").start();
//        new Thread(pro, "生产者C").start();
//        new Thread(consumer, "消费者D").start();

        // 测试3(从wait()方法被唤醒后,先进行条件判断然后再执行后续逻辑)
        Clerk clerk3 = new Clerk3();
        Producer pro = new Producer(clerk3);
        Consumer consumer = new Consumer(clerk3);
        new Thread(pro, "生产者A").start();
        new Thread(consumer, "消费者B").start();
        new Thread(pro, "生产者C").start();
        new Thread(consumer, "消费者D").start();
    }
}

/**
 * 店员类3
 */
class Clerk3 implements Clerk {
    private int product = 0;

    // 进货
    public synchronized void get() {
        while (product >= 1) {// 此处变成了循环判断
            System.out.println("产品已满");
            try {
                this.wait();// 为了避免虚假唤醒问题应该总是使用在循环中
            } catch (InterruptedException e) {}
        }
        System.out.println(Thread.currentThread().getName() + " : " + ++product);
        this.notifyAll();
    }
    // 卖货
    public synchronized void sell() {
        while (product <= 0) {// 此处变成了循环判断
            System.out.println("缺货");
            try {
                this.wait();// 为了避免虚假唤醒问题,应该总是使用在循环中
            } catch (InterruptedException e) {}
        }
        System.out.println(Thread.currentThread().getName() + " : " + --product);
        this.notifyAll();
    }
}
/**
 * 店员类2
 */
class Clerk2 implements Clerk {
    private int product = 0;

    // 进货
    public synchronized void get() {
        if (product >= 1) {
            System.out.println("产品已满");
            try {
                this.wait();
            } catch (InterruptedException e) {}
        }// 此处去掉了else
        System.out.println(Thread.currentThread().getName() + " : " + ++product);
        this.notifyAll();
    }
    // 卖货
    public synchronized void sell() {
        if (product <= 0) {
            System.out.println("缺货");
            try {
                this.wait();
            } catch (InterruptedException e) {}
        }// 此处去掉了else
        System.out.println(Thread.currentThread().getName() + " : " + --product);
        this.notifyAll();
    }
}

/**
 * 店员类1
 */
class Clerk1 implements Clerk {
    private int product = 0;

    // 进货
    public synchronized void get() {
        if (product >= 1) {
            System.out.println("产品已满");
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        } else {
            System.out.println(Thread.currentThread().getName() + " : " + ++product);
            this.notifyAll();
        }
    }

    // 卖货
    public synchronized void sell() {
        if (product <= 0) {
            System.out.println("缺货");
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        } else {
            System.out.println(Thread.currentThread().getName() + " : " + --product);
            this.notifyAll();
        }
    }
}

/**
 * 生产者
 */
class Producer implements Runnable {
    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "执行次数: " + i);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
            }
            clerk.get();
        }
    }
}

/**
 * 消费者
 */
class Consumer implements Runnable {
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "执行次数: " + i);
            clerk.sell();
        }
    }
}

/**
 * 店员接口
 */
interface Clerk {
    void get();

    void sell();
}

